#include <string.h>
#include <stdio.h>
#include "cli_api.h"
#include "bootpara_cli.h"
#include "bootpara_deal.h"
#include "board_partitions.h"


static void bootpara_command_usage(const char *prog)
{
    printf("  Usage: %s [OPTIONS]\r\n", prog);
    printf("  Options:\r\n");
    printf("  set baudrate   value                      Set the bootloader baudrate\r\n");
    printf("  set bootmode   [boot|down]                Set the bootloader workmode\r\n");
    printf("  set app_state  [valid|invalid]            Set the app state\r\n");
    printf("  set boot_state [first|non-first]          Set the boot state\r\n");
    printf("  set boot_part  [app|ota]                  Set the boot part\r\n");
    printf("  set all_params [baudrate|bootmode|                         \r\n");
    printf("                 app_state|bootstate|                        \r\n");
    printf("                 bootpart]                  Set ALL boot params\r\n");
    printf("  get baudrate                              Get the bootloader baudrate\r\n");
    printf("  get bootmode                              Get the bootloader workmode\r\n");
    printf("  get app_state                             Get the app state\r\n");
    printf("  get boot_state                            Get the boot state\r\n");
    printf("  get boot_part                             Get the boot part\r\n");
    printf("  get all_params                            Get ALL boot params\r\n");
    printf("\r\n");
}



static int setup_baudrate(char *param)
{
    uint32_t baudrate = 0;
    int ret = SUCCESS;

    baudrate = strtoul(param, NULL, 10);
    cli_printf("baudrate : %d.\n", baudrate);
    if (SUCCESS != set_baudrate(baudrate)) {
        cli_printf("set baudrate error.\n");
        ret = FAILURE;
    }

    return ret;
}

static int setup_bootmode(char *param)
{
    uint8_t type = 0;
    int ret = SUCCESS;
 
    if (!strcmp(param, "boot")) {
        type = BOOT_MODE_NUM;
        cli_printf("set bootmode to boot.\n");
    }    
    else if (!strcmp(param, "down")) {
        type = DOWN_MODE_NUM;
        cli_printf("set bootmode to down.\n");
    } else {
        cli_printf("param invalid!\n");
        return FAILURE;
    }
    if (SUCCESS != set_bootmode(type)) {
        cli_printf("set bootmode error.\n");
        ret = FAILURE;
    }

    return ret;
}

static int setup_app_state(char *param)
{
    uint8_t type = 0;
    int ret = SUCCESS;

    if (!strcmp(param, "valid")) {
        type = APP_VALID_NUM;
        cli_printf("set app state to valid.\n");
    }
    else if (!strcmp(param, "invalid")) {
        type = APP_INVALID_NUM;
        cli_printf("set app state to invalid.\n");
    } else {
        cli_printf("param invalid!\n");
        return FAILURE;
    }
    if (SUCCESS != set_app_state(type)) {
        cli_printf("set app state error.\n");
        ret = FAILURE;
    }

    return ret;
}

static int setup_boot_state(char *param)
{
    uint8_t type = 0;
    int ret = SUCCESS;

    if (!strcmp(param, "first")) {
        type = FIRST_BOOT_NUM;
        cli_printf("set boot state to first.\n");
    }
    else if (!strcmp(param, "non-first")) {
        type = NON_FIRST_BOOT_NUM;
        cli_printf("set boot state to non-first.\n");
    } else {
        cli_printf("param invalid!\n");
        return FAILURE;
    }
    if (SUCCESS != set_boot_state(type)) {
        cli_printf("set boot state error.\n");
        ret = FAILURE;
    }

    return ret;
}

static int setup_boot_part(char *param)
{
    uint8_t type = 0;
    int ret = SUCCESS;

    if (!strcmp(param, "app")) {
        type = APP_PART_NUM;
        cli_printf("set boot part to app.\n");
    }
    else if (!strcmp(param, "ota")) {
        type = OTA_PART_NUM;
        cli_printf("set boot part to ota.\n");
    } else {
        cli_printf("param invalid!\n");
        return FAILURE;
    }
    if (SUCCESS != set_boot_part(type)) {
        cli_printf("set boot state error.\n");
        ret = FAILURE;
    }

    return ret;
}

static int setup_all_bootparams(int argc, char **argv)
{
    uint32_t baudrate = 0;
    uint32_t bootmode = 0;
    uint32_t app_state = 0;
    uint32_t boot_state = 0;
    uint32_t boot_part = 0;
    int ret = SUCCESS;

    boot_param_cfg_list_t boot_param_cfg_list;
    memset(&boot_param_cfg_list, 0, sizeof(boot_param_cfg_list_t));
    baudrate = strtoul(argv[3], NULL, 10);
    printf("baudrate : %d.\n", baudrate);
    if (!strcmp(argv[4], "boot")) {
        bootmode = BOOT_MODE;
        printf("set bootmode to boot.\n");
    }    
    else if (!strcmp(argv[4], "down")) {
        bootmode = DOWN_MODE;
        printf("set bootmode to down.\n");
    } else {
        printf("bootmode invalid!\n");
        return FAILURE;
    }
    if (!strcmp(argv[5], "valid")) {
        app_state = APP_VALID;
        printf("set app state to valid.\n");
    }
    else if (!strcmp(argv[5], "invalid")) {
        app_state = APP_INVALID;
        printf("set app state to invalid.\n");
    } else {
        printf("app state invalid!\n");
        return FAILURE;
    }
    if (!strcmp(argv[6], "first")) {
        boot_state = FIRST_BOOT;
        printf("set boot state to first.\n");
    }
    else if (!strcmp(argv[6], "non-first")) {
        boot_state = NON_FIRST_BOOT;
        printf("set boot state to non-first.\n");
    } else {
        printf("boot state invalid!\n");
        return FAILURE;
    }
    if (!strcmp(argv[7], "app")) {
        boot_part = APP_PART;
        printf("set boot part to app.\n");
    }
    else if (!strcmp(argv[7], "ota")) {
        boot_part = OTA_PART;
        printf("set boot part to ota.\n");
    } else {
        printf("boot part invalid!\n");
        return FAILURE;
    }

    boot_param_cfg_list.baudrate_para_cfg.flag = BOOT_PARA_NEED_SET;
    boot_param_cfg_list.baudrate_para_cfg.para = baudrate;
    boot_param_cfg_list.bootmode_para_cfg.flag = BOOT_PARA_NEED_SET;
    boot_param_cfg_list.bootmode_para_cfg.para = bootmode;
    boot_param_cfg_list.app_state_para_cfg.flag = BOOT_PARA_NEED_SET;
    boot_param_cfg_list.app_state_para_cfg.para = app_state;
    boot_param_cfg_list.boot_state_para_cfg.flag = BOOT_PARA_NEED_SET;
    boot_param_cfg_list.boot_state_para_cfg.para = boot_state;
    boot_param_cfg_list.boot_part_para_cfg.flag = BOOT_PARA_NEED_SET;
    boot_param_cfg_list.boot_part_para_cfg.para = boot_part;
    if (SUCCESS != set_bootpara_list(&boot_param_cfg_list)) {
        printf("set all boot params error.\n");
        ret = FAILURE;
    }

    return ret;
}

static int set_bootpara(int argc, char **argv)
{
    int ret = SUCCESS;
    
    if (!strcmp(argv[2], "baudrate")) 
        ret = setup_baudrate(argv[3]);
    else if (!strcmp(argv[2], "bootmode")) 
        ret = setup_bootmode(argv[3]);
    else if (!strcmp(argv[2], "app_state")) 
        ret = setup_app_state(argv[3]);
    else if (!strcmp(argv[2], "boot_state")) 
        ret = setup_boot_state(argv[3]);              
    else if (!strcmp(argv[2], "boot_part")) 
        ret = setup_boot_part(argv[3]);              
    else if (!strcmp(argv[2], "all_params")) 
        ret = setup_all_bootparams(argc, argv);
    else {
        cli_printf("param invalid!\n");
        ret = FAILURE;
    }

    return ret;
}

static void print_baudrate(void)
{
    printf("baudrate : %d.\n", get_baudrate());

    return;
}

static void print_bootmode(void)
{
    uint32_t mode = 0;
    char *ptr = NULL;

    mode = get_bootmode();
    if (DOWN_MODE == mode)
        ptr = "down";
    else if(BOOT_MODE == mode)
        ptr = "boot";
    printf("bootmode : %s.\n", ptr);

    return;
}

static void print_app_state(void)
{
    uint32_t mode = 0;
    char *ptr = NULL;

    mode = get_app_state();
    if (APP_INVALID == mode)
        ptr = "invalid";
    else if(APP_VALID == mode)
        ptr = "valid";
    printf("app state : %s.\n", ptr);

    return;
}

static void print_boot_state(void)
{
    uint32_t mode = 0;
    char *ptr = NULL;

    mode = get_boot_state();
    if (FIRST_BOOT == mode)
        ptr = "first";
    else if(NON_FIRST_BOOT == mode)
        ptr = "non-first";
    printf("boot state : %s.\n", ptr);

    return;
}

static void print_boot_part(void)
{
    uint32_t mode = 0;
    char *ptr = NULL;

    mode = get_boot_part();
    if (APP_PART == mode)
        ptr = "app";
    else if(OTA_PART == mode)
        ptr = "ota";
    printf("boot part : %s.\n", ptr);

    return;
}

static void print_all_bootparams(void)
{
    print_baudrate();
    print_bootmode();
    print_app_state();
    print_boot_state();
    print_boot_part();

    return;
}

static int get_bootpara(int argc, char **argv)
{
    int ret = SUCCESS;

    if (!strcmp(argv[2], "baudrate"))
        print_baudrate();
    else if (!strcmp(argv[2], "bootmode")) 
        print_bootmode();
    else if (!strcmp(argv[2], "app_state")) 
        print_app_state();
    else if (!strcmp(argv[2], "boot_state"))
        print_boot_state(); 
    else if (!strcmp(argv[2], "boot_part"))
        print_boot_part(); 
    else if (!strcmp(argv[2], "all_params")) {
        print_all_bootparams();
    } else {
        cli_printf("param invalid!\n");
        ret = FAILURE;
    }

    return ret;
}

void bootpara_command(char *outbuf, int len, int argc, char **argv)
{
    if (argc == 1) {
        bootpara_command_usage(argv[0]);
        return;
    }
    if (!strcmp(argv[1], "set")) {
        set_bootpara(argc, argv);
    } else if (!strcmp(argv[1], "get")) {
        get_bootpara(argc, argv);
    } else {
        cli_printf("param invalid!\n");
    }

    return;
}


static const struct cli_command_st bootpara_cli_cmd[] = 
{
    [0] =
    {
        .name            = "bootpara",
        .help            = "bootpara [set|get bootpara]",
        .function        = bootpara_command
    },
};

int bootpara_cli_register(void) 
{
    int ret = 0;

    ret = cli_register_commands(bootpara_cli_cmd, sizeof(bootpara_cli_cmd)/sizeof(struct cli_command_st));
    if (ret != CLI_OK) {
        printf("bootpara cli register fail\n");
        return ret;
    }

    return CLI_OK;
}